(function (window) {
    'use strict';

    /**
     * Navigation Timing API helpers
     * timing.getTimes();
     **/
    window.timing = window.timing || {
        /**
         * Outputs extended measurements using Navigation Timing API
         * @param  Object opts Options (simple (bool) - opts out of full data view)
         * @return Object      measurements
         */
        getTimes: function (opts) {
            var performance = window.performance || window.webkitPerformance || window.msPerformance || window.mozPerformance;

            if (performance === undefined) {
                return false;
            }

            var timing = performance.timing;
            var api = {};
            opts = opts || {};

            if (timing) {
                if (opts && !opts.simple) {
                    for (var k in timing) {
                        // hasOwnProperty does not work because properties are
                        // added by modifying the object prototype
                        if (isNumeric(timing[k])) {
                            api[k] = parseFloat(timing[k]);
                        }
                    }
                }


                // Time to first paint
                if (api.firstPaint === undefined) {
                    // All times are relative times to the start time within the
                    // same objects
                    var firstPaint = 0;

                    // Chrome
                    if (window.chrome && window.chrome.loadTimes) {
                        // Convert to ms
                        firstPaint = window.chrome.loadTimes().firstPaintTime * 1000;
                        api.firstPaintTime = firstPaint - timing.navigationStart;
                    }
                    // IE
                    else if (typeof timing.msFirstPaint === 'number') {
                        firstPaint = timing.msFirstPaint;
                        api.firstPaintTime = firstPaint - timing.navigationStart;
                    }
                    // Firefox
                    // This will use the first times after MozAfterPaint fires
                    //else if (timing.navigationStart && typeof InstallTrigger !== 'undefined') {
                    //    api.firstPaint = timing.navigationStart;
                    //    api.firstPaintTime = mozFirstPaintTime - timing.navigationStart;
                    //}
                    if (opts && !opts.simple) {
                        api.firstPaint = firstPaint;
                    }
                }

                // Total time from start to load
                api.loadTime = timing.loadEventEnd - timing.fetchStart;
                // Time spent constructing the DOM tree
                api.domReadyTime = timing.domComplete - timing.domInteractive;
                // Time consumed preparing the new page
                api.readyStart = timing.fetchStart - timing.navigationStart;
                // Time spent during redirection
                api.redirectTime = timing.redirectEnd - timing.redirectStart;
                // AppCache
                api.appcacheTime = timing.domainLookupStart - timing.fetchStart;
                // Time spent unloading documents
                api.unloadEventTime = timing.unloadEventEnd - timing.unloadEventStart;
                // DNS query time
                api.lookupDomainTime = timing.domainLookupEnd - timing.domainLookupStart;
                // TCP connection time
                api.connectTime = timing.connectEnd - timing.connectStart;
                // Time spent during the request
                api.requestTime = timing.responseEnd - timing.requestStart;
                // Request to completion of the DOM loading
                api.initDomTreeTime = timing.domInteractive - timing.responseEnd;
                // Load event time
                api.loadEventTime = timing.loadEventEnd - timing.loadEventStart;
            }

            return api;
        },
        /**
         * Uses console.table() to print a complete table of timing information
         * @param  Object opts Options (simple (bool) - opts out of full data view)
         */
        printTable: function (opts) {
            var table = {};
            var data = this.getTimes(opts) || {};
            Object.keys(data).sort().forEach(function (k) {
                table[k] = {
                    ms: data[k],
                    s: +((data[k] / 1000).toFixed(2))
                };
            });
            console.table(table);
        },
        /**
         * Uses console.table() to print a summary table of timing information
         */
        printSimpleTable: function () {
            this.printTable({ simple: true });
        },

        getSimpleResult: function () {
            var fullData = this.getTimes();

            return {
                totalTime: fullData.loadTime,
                domTime: fullData.initDomTreeTime
            }
        }
    };

    window.benchamark = {
        startRecord: function () {
            var limitTimes = sessionStorage.getItem("limit") || "10";
            limitTimes = parseInt(limitTimes);

            var data = window.timing.getSimpleResult();

            var isStartRecorded = sessionStorage.getItem("isStartRecorded");
            var records;
            if (isStartRecorded) {
                records = JSON.parse(sessionStorage.getItem("timingRecords"));
                records.push(data);
            } else {
                sessionStorage.setItem("isStartRecorded", 1);
                records = [data];
            }

            var totalStatistics = calcStatistics(records.map(function (data) {
                return data.totalTime;
            }));
            var domStatistics = calcStatistics(records.map(function (data) {
                return data.domTime;
            }));

            sessionStorage.setItem("timingRecords", JSON.stringify(records));

            sessionStorage.setItem("recordSize", records.length);

            sessionStorage.setItem("totalSum", totalStatistics.sum);
            sessionStorage.setItem("totalAvg", totalStatistics.average);
            sessionStorage.setItem("totalVariance", totalStatistics.variance);
            sessionStorage.setItem("totalStandardDeviation", totalStatistics.standardDeviation);

            sessionStorage.setItem("domSum", domStatistics.sum);
            sessionStorage.setItem("domAvg", domStatistics.average);
            sessionStorage.setItem("domVariance", domStatistics.variance);
            sessionStorage.setItem("domStandardDeviation", domStatistics.standardDeviation);

            if (records.length < limitTimes) {
                location.reload();
            }
        },
        exportToExcel: function () {
            var script = document.createElement("script");
            script.src = "https://unpkg.com/xlsx/dist/xlsx.full.min.js";
            script.addEventListener("load", function () {
                setTimeout(() => {
                    dataToExcel();
                }, 1000);

                window.benchamark.exportToExcel = function () {
                    dataToExcel();
                }
            });
            document.body.appendChild(script);
        }
    }

    function calcStatistics(dataList) {
        var size = dataList.length;
        var sum = dataList.reduce(function (preVal, curVal) {
            return preVal + curVal;
        }, 0);
        var average = sum / size;
        var variance = dataList.reduce(function (preVal, curVal) {
            return preVal + Math.pow(curVal - average, 2);
        }, 0) / size;
        var standardDeviation = Math.sqrt(variance);

        return {
            size: size,
            sum: sum,
            average: average,
            variance: variance,
            standardDeviation: standardDeviation
        }
    }

    function dataToExcel() {
        var isStartRecorded = sessionStorage.getItem("isStartRecorded");
        var records = [];
        if (isStartRecorded) {
            records = JSON.parse(sessionStorage.getItem("timingRecords"));
        }

        console.log("=== dataToExcel ===");
        console.log(records);

        var wb = XLSX.utils.book_new();
        //TODO ...
    }

    function isNumeric(n) {
        return !isNaN(parseFloat(n)) && isFinite(n);
    }

    // Expose as a commonjs module
    if (typeof module !== 'undefined' && module.exports) {
        module.exports = window.timing;
    }

})(typeof window !== 'undefined' ? window : {});


document.addEventListener('DOMContentLoaded', function () {
    setTimeout(() => {
        window.benchamark.startRecord();
    }, 3000);

}, false);